use crate::app::error::MyError;
use crate::app::error::MyError::MsgError;
use serde_json::{Map, Value};

pub fn map_myerror<E: std::error::Error>(err: E) -> MyError {
    MsgError(err.to_string())
}

pub fn has_same_structure(value1: &Value, value2: &Value) -> bool {
    match (value1, value2) {
        (Value::Object(obj1), Value::Object(obj2)) => has_same_object_structure(obj1, obj2),
        (Value::Array(arr1), Value::Array(arr2)) => has_same_array_structure(arr1, arr2),
        _ => {
            (value1.is_boolean() && value2.is_boolean())
                || (value1.is_number() && value2.is_number())
                || (value1.is_null() && value2.is_null())
                || (value1.is_string() && value2.is_string())
        }
    }
}

pub fn has_same_structure_with_request_body(state_structure: &Value, body: &Value) -> bool {
    match (state_structure, body) {
        (Value::Object(obj1), Value::Object(obj2)) => has_same_object_structure(obj1, obj2),
        (Value::Array(arr1), Value::Array(arr2)) => has_same_array_structure(arr1, arr2),
        (Value::Array(arr), Value::Object(_)) => {
            let ele = &arr[0];
            has_same_structure(ele, body)
        }
        _ => false,
    }
}

pub fn has_same_object_structure(obj1: &Map<String, Value>, obj2: &Map<String, Value>) -> bool {
    if obj1.len() != obj2.len() {
        return false;
    }

    for (key, value1) in obj1 {
        if let Some(value2) = obj2.get(key) {
            if !has_same_structure(value1, value2) {
                return false;
            }
        } else {
            return false;
        }
    }

    true
}

pub fn has_same_array_structure(arr1: &[Value], arr2: &[Value]) -> bool {
    if arr1.len() != arr2.len() {
        return false;
    }

    for (value1, value2) in arr1.iter().zip(arr2.iter()) {
        if !has_same_structure(value1, value2) {
            return false;
        }
    }

    true
}
